# To change this template, choose Tools | Templates
# and open the template in the editor.

require 'utility/vec_utils'

class ExponentialRegression
  attr_accessor :exp, :amplitude, :error
  def initialize(train_matrix, train_vector_y)
    log_vect= VecUtils.logarizzatore(train_vector_y)
    @exp= self.exponential(train_matrix,log_vect)
    @amplitude= Math.exp((VecUtils.sum(log_vect)-self.exp*VecUtils.sum(VecUtils.matrix_av_vector(train_matrix)))/log_vect.size)
    @error= (10**self.pendenza(log_vect, train_matrix))
  end
  # Update delle variabili
  def  update(train_matrix, train_vector_y)
     log_vect= VecUtils.logarizzatore(train_vector_y)
     e= self.exponential(train_matrix,log_vect)
     uexp= e*self.exp
     ua= Math.exp((VecUtils.sum(log_vect)-uexp*VecUtils.sum(VecUtils.matrix_av_vector(train_matrix)))/log_vect.size)
     uerror= (10**self.pendenza(log_vect, train_matrix))

    self.exp= (self.exp+uexp)/2
    self.amplitude= (self.amplitude+ua)/2
    self.error= (self.error+uerror)/2
  end
  # Funzione per il calcolo della pendenza
  def pendenza(train_vector_y, train_matrix)
    pendenza= 0

    train_vector_x= VecUtils.matrix_av_vector(train_matrix)
    av_train_vector_x= VecUtils.average(train_vector_x)

    av_train_vector_y= VecUtils.average(train_vector_y)

    nominatore = 0
    denominatore = 0

    (0..train_vector_y.size-1).each{|i|
      nominatore= nominatore + ((train_vector_x[i]-av_train_vector_x)*(train_vector_y[i]-av_train_vector_y))
      denominatore= denominatore + (train_vector_x[i]-av_train_vector_x)**2
    }


    pendenza= nominatore/denominatore

    return pendenza
  end
  def exponential(train_matrix,train_vector_y)
    exp_v= 0
    vector_av_x= VecUtils.matrix_av_vector(train_matrix)

    nominatore= vector_av_x.size*VecUtils.mul_sum(vector_av_x, train_vector_y)-VecUtils.sum(vector_av_x)*VecUtils.sum(train_vector_y)
    denominatore= vector_av_x.size*vector_av_x.inject{ |sum, el| sum + el**2 }.to_f-VecUtils.sum(vector_av_x)**2

    exp_v= nominatore/denominatore

    return exp_v
  end
  def regressione(matrix_x)
    av_vector_x= VecUtils.matrix_av_vector(matrix_x)
    exp_reg= []
      
    av_vector_x.each{|x|
      # value= self.amplitude * Math.exp(self.exp*x)
      value= self.amplitude * Math.exp(self.exp*x)
      exp_reg.push(value.round)
    }

    return exp_reg
  end
  def exp
    @exp
  end
  def amplitude
    @amplitude
  end
  def error
    @error
  end
  def ExponentialRegression.test()
    v3=[[0, 1, 2, 3, 4, 5, 6]]
    v4= [25, 38, 58, 89, 135, 206, 315]
    r= ExponentialRegression.new(v3,v4)

    p '<---------------------------->'
    p 'train value'
    p 'b---> 0,42'
    p r.exp
    p 'a---> 24,96'
    p r.amplitude
    p r.error
    p 'fine value'
    p 'valore atteso---> 480'
    p r.regressione([[7]])
    p '<---------------------------->'
  end
    def ExponentialRegression.test2()
    x = [[71,73,64,65,61,70,65,72,63,67,64]]
    y = [160,183,154, 168, 159, 180, 145, 210, 132, 168, 141]

    r= ExponentialRegression.new(x,y)

    p '<---------------------------->'
    p 'Test regressione esponenziale'
    p 'Dati'
    p 'b---> 0,42'
    p r.exp
    p 'a---> 24,96'
    p r.amplitude
    p r.error
    p 'fine dati'
    p '<--------->'
    p 'test con valore 70'
    p 'valore atteso: [176.51,185]'
    p r.regressione([[70,72]])
    p '<---------------------------->'
  end
end
